const _ = require('lodash');
const moment = require('moment');
const async = require('async');
const app = require('../server');
const commonService = require('./common');
const customService = require('./custom');
const enums = require('../enums');
const handlebars = require('handlebars');

const emailSendStatus = {
  cancel: 'cancel',
  approve: 'approve',
  noBusinessApprove: 'noBusinessApprove',
  rejected: 'rejected',
  submit: 'submit',
  complete: 'complete',
  forword: 'forword',
  return: 'return',
  reSubmit: 'reSubmit',
};
const models = app.models;
const { event: customEventService, condition: customConditionService } = customService;

// 普通逻辑发送email
function handlEmailSendEvent(form, flow, formDetail, approvalList, isCancel, reSubmit) {
  const employeeId = commonService.getEmployeeId();
  const approvalStep = formDetail.approvalStep;
  let currentApproval = [];
  let nextStepApproval = [];
  const requester = formDetail.owner();
  let status = '';
  if (isCancel) {
    // 判断是form1 的取消还是form2 的return
    status = isCancel == emailSendStatus.return ? emailSendStatus.return : emailSendStatus.cancel;
    currentApproval = _.filter(approvalList, { approvalStep });
    nextStepApproval = _.filter(approvalList, { approvalStep: approvalStep + 1 });
  } else {
    currentApproval = _.filter(approvalList, { approverEmployeeId: employeeId, approvalStep: approvalStep - 1 });
    nextStepApproval = _.filter(approvalList, { approvalStep });
    // 没选Business approval
    if (currentApproval.length == 0) {
      currentApproval = _.filter(approvalList, { approverEmployeeId: employeeId, approvalStep: approvalStep - 2 });
    }
    if (formDetail.formStatus > enums.formStatus.submitted && formDetail.formStatus < enums.formStatus.completed) {
      if (!!nextStepApproval || !!currentApproval) {
        // 当不选bs时
        nextStepApproval[0].approvalStep == 3 && currentApproval[0].approvalStep == 1 ? status = emailSendStatus.noBusinessApprove : status = emailSendStatus.approve;
      }
    }
    if (formDetail.formStatus < enums.formStatus.submitted && formDetail.formStatus > enums.formStatus.saved) {
      status = emailSendStatus.rejected;
    }
    if (formDetail.formStatus == enums.formStatus.submitted) {
      status = reSubmit == 'true' ? emailSendStatus.reSubmit : emailSendStatus.submit;
    }
    if (formDetail.formStatus == enums.formStatus.completed) {
      status = emailSendStatus.complete;
      // MRF提交approvalStep少了1
      if (form.id == 2) {
        currentApproval = _.filter(approvalList, { approvalStep });
        nextStepApproval = _.filter(approvalList, { approvalStep: approvalStep + 1 });
      }
    }
  }
  let emailSendToList;
  // 有于当前模板里的
  let approver = {};
  let nextApprover = {};
  // 判断是否为申请人提交
  if (currentApproval.length === 0) {
    const stepId = nextStepApproval[0].stepId;
    emailSendToList = getStepEmailAcitonList(stepId, flow.flowRun.steps, status, 0);
    nextApprover = nextStepApproval[0].approver();
  } else {
    let stepId = currentApproval[0].$stepId;
    //  判断是否还有下一步
    if (nextStepApproval.length === 0) {
      approver = currentApproval[0].approver();
    } else {
      approver = currentApproval[0].approver();
      approver.approvalName = currentApproval[0].approvalName;
      if (nextStepApproval[0].formId == 2 && nextStepApproval[0].flowId == 2 && nextStepApproval[0].stepId == 2) {
        nextApprover = formDetail.formDetail.business;
      } else {
        nextApprover = nextStepApproval[0].approver();
      }
    }
    approver.approvalName = currentApproval[0].approvalName;
    stepId == 3 && status == emailSendStatus.complete && nextStepApproval.length !== 0 ? stepId = nextStepApproval[0].$stepId : 0;
    emailSendToList = getStepEmailAcitonList(stepId, flow.flowRun.steps, status, (approvalStep - 1));
  }
  // 遍历需要发送的emailSend
  sendEmailForEach(emailSendToList, form, formDetail, requester, approver, nextApprover, approvalList);
}

// 转发发送邮件
function handlForwordEmailSendEvent(form, flow, formDetail, forwordBeforeApprover, approvalList) {
  const nextStepApproval = _.filter(approvalList);
  const { SysUser: userModel } = models;
  const requester = formDetail.owner;
  const status = emailSendStatus.forword;
  const approver = forwordBeforeApprover;
  const stepId = nextStepApproval[0].stepId;
  const emailSendToList = getStepEmailAcitonList(stepId, flow.flowRun.steps, status, 0);
  const nextApprover = (next) => {
    userModel.findOne({ where: { employeeId: nextStepApproval[0].approverEmployeeId } }, next);
  };
  async.waterfall([nextApprover], (err, result) => {
    // formDetail 格式转换
    formDetail.createdAt = new Date(formDetail.createdAt);
    sendEmailForEach(emailSendToList, form, formDetail, requester, approver, result, approvalList);
  });
}

function handlRevocationFormEmailSendEvent(form, flow, formDetail, approvalList, approvalListEmailNeed) {
  const approvalStep = formDetail.approvalStep;
  const currentApproval = approvalList;
  const requester = formDetail.owner;
  const status = emailSendStatus.rejected;
  const stepId = 4;
  const emailSendToList = getStepEmailAcitonList(stepId, flow.flowRun.steps, status, (approvalStep - 1));
  // 有于当前模板里的
  const approver = currentApproval[0].approver();
  const nextApprover = {};
  // 遍历需要发送的emailSend
  sendEmailForEach(emailSendToList, form, formDetail, requester, approver, nextApprover, approvalListEmailNeed);
}

// 定时器发送邮件
function sendEmailReminder() {
  const models = commonService.getModels();
  const { WfTemplate: templateModel, WfRunFlowDetail: approvalDetailModel } = models;
  const reminderTime = 24 * 60 * 60 * 1000;
  const emailTemplate = (next) => {
    // id = 16 为Reminder的模板
    templateModel.findOne({ where: { id: 16 } }, next);
  };
  const approvalDetail = (template, next) => {
    const option = {
      where: {
        flowId: '2',
        approvalStatus: 0,
        stepId: 1,
        updatedAt: {
          between: [Date.now() - (3 * reminderTime), Date.now() - (2 * reminderTime)],
        },
      },
      include: ['approver', 'formDetail'],
      order: 'id ASC',
    };
    approvalDetailModel.find(option, (err, result) => {
      _.forEach(result, (item, index) => {
        // 去掉转发之前的人
        for (let i = index + 1; i < result.length; i++) {
          if (item.instanceId == result[i].instanceId) return;
        }
        const formDetail = item.formDetail();
        try {
          const options = {
            from: process.env.EMAIL_SENDER,
            to: item.approver().email,
            subject: commonService.compileEmailTemplate(template.subject, { host: process.env.EMAIL_HOST, formDetail }),
            html: commonService.compileEmailTemplate(template.emailBody, { host: process.env.EMAIL_HOST, formDetail }),
          };
          if (!_.isEmpty(template.priority)) {
            options.priority = template.priority;
          }
          commonService.sendEmail(options, error => !_.isEmpty(error) && console.log(error));
        } catch (error) {
          throw (error);
        }
      });
      next();
    });
  };

  async.waterfall([emailTemplate, approvalDetail], err => err);
}
// 根据step下的节点发送邮件
function sendEmailForEach(emailSendToList, form, formDetail, requester, approver, nextApprover, approvalList) {
  const { WfTemplate: templateModel } = models;
  // 遍历需要发送的emailSend
  _.forEach(emailSendToList, (item) => {
    const to = (next) => {
      const dataList = [];
      const toEmailArr = [];
      // 判断是否为给申请人或审核人发送的
      if (item.user.roleId != '-1' && item.user.roleId != '-2' && item.user.roleId != '-3' && item.user.roleId != '-4' && item.user.roleId != '-5' && item.user.roleId != '-1,-4') {
        let sql = 'SELECT u.email FROM elanco_sys.sys_user_role_mapping as ru LEFT JOIN elanco_sys.sys_user as u on ru.user_employee_id = u.employee_id where';
        if (!_.isEmpty(item.user.roleId)) {
          sql += ' ru.role_id in (';
          item.user.roleId.split(',').forEach((item1, index) => {
            if (item1 == '-2') {
              toEmailArr.push(nextApprover.email);
            } else {
              dataList.push(item1);
              if (index != 0) sql += ',';
              sql += `$${dataList.length}`;
            }
          });
          sql += ')';
        }
        if (!_.isEmpty(item.user.roleId) && !_.isEmpty(item.user.userId)) {
          sql += ' or';
        }
        if (!_.isEmpty(item.user.userId)) {
          sql += ' ru.role_id in (';
          item.user.userId.split(',').forEach((item1, index) => {
            dataList.push(item1);
            if (index != 0) sql += ',';
            sql += `$${dataList.length}`;
          });
          sql += ')';
        }
        sql += ' group by u.email';
        commonService.executeSql(sql, dataList, (err, data) => {
          _.forEach(data, (dataItem) => {
            toEmailArr.push(dataItem.email);
          });
          next(null, toEmailArr);
        });
      }
      // -1 为申请人
      if (item.user.roleId == '-1') {
        next(null, [requester.email]);
      }
      // -2 为下一步审核人
      if (item.user.roleId == '-2') {
        next(null, [nextApprover.email]);
      }
      // -3 为当前审核人
      if (item.user.roleId == '-3') {
        approver.email ? next(null, [approver.email]) : next(null, [nextApprover.email]);
      }
      // -4 为Hiring Manager
      if (item.user.roleId == '-4') {
        next(null, [formDetail.formDetail.hiringManager.email]);
      }
      // -5 为business提交是的er
      if (item.user.roleId == '-5') {
        next(null, [approvalList[0].approver.email]);
      }
      // -6 为所有审批过的人
      if (item.user.roleId == '-6') {
        const dataList = [];
        _.forEach(approvalList, (approvalListItem) => {
          // 可能需要测试是否加上formStatus<99
          dataList.push(approvalListItem.approver().email);
        });
        next(null, [dataList]);
      }
      // -1,-4  为申请人和Hiring Manager
      if (item.user.roleId == '-1,-4') {
        next(null, [requester.email, formDetail.formDetail.hiringManager.email]);
      }
    };
    const cc = (toEmail, next) => {
      const dataList = [];
      let data = [];
      if (!_.isEmpty(item.cc.roleId) || !_.isEmpty(item.cc.userId)) {
        let sql = 'SELECT u.email FROM elanco_sys.sys_user_role_mapping as ru LEFT JOIN elanco_sys.sys_user as u on ru.user_employee_id = u.employee_id where';
        if (!_.isEmpty(item.cc.roleId)) {
          sql += ' ru.role_id in (';
          item.cc.roleId.split(',').forEach((item1, index) => {
            // 判断是否为给申请人或审核人发送的
            if (item1 != '-1' && item1 != '-2' && item1 != '-3' && item1 != '-4' && item1 != '-5' && item1 != '-1,-4') {
              dataList.push(item1);
              if (index != 0) sql += ',';
              sql += `$${dataList.length}`;
            }
            // -1 为申请人
            if (item1 == '-1') {
              data.push(requester.email);
            }
            // -2 为下一步审核人
            if (item1 == '-2') {
              data.push(nextApprover.email);
            }
            // -3 为当前审核人
            if (item1 == '-3') {
              approver.email ? data.push(approver.email) : data.push(nextApprover.email);
            }
            if (item1 == '-4') {
              data.push(formDetail.formDetail.hiringManager.email);
            }
            // -5 为business提交是的er
            if (item1 == '-5') {
              data.push(approvalList[0].approver().email);
            }
            // 所有审核果的人
            if (item1 == '-6') {
              _.forEach(approvalList, (approvalListItem) => {
                approvalListItem.approver.email ? data.push(approvalListItem.approver.email) : data.push(approvalListItem.approver().email);
              });
            }
            if (item1 == '-1,-4') {
              data.push(requester.email, formDetail.formDetail.hiringManager.email);
            }
          });
          sql += ')';
        }
        if (!_.isEmpty(item.cc.roleId) && !_.isEmpty(item.cc.userId)) {
          sql += ' or';
        }
        if (!_.isEmpty(item.cc.userId)) {
          sql += ' ru.role_id in (';
          item.cc.userId.split(',').forEach((item1, index) => {
            dataList.push(item1);
            if (index != 0) sql += ',';
            sql += `$${dataList.length}`;
          });
          sql += ')';
        }
        sql += ' group by u.email';
        commonService.executeSql(sql, dataList, (err, result) => {
          toEmail = _.compact(_.uniq(toEmail));
          _.forEach(result, (dataItem) => {
            data.push(dataItem.email);
          });
          for (let i = 0; i < toEmail.length; i++) {
            for (let j = 0; j < data.length; j++) {
              if (data[j] == toEmail[i]) {
                data.splice(j, 1);
                j--;
              }
            }
          }
          data = _.compact(_.uniq(data));
          next(null, toEmail, data);
        });
      } else {
        next(null, toEmail, []);
      }
    };
    // 发送sendEmail请求，特殊需求可以抽离出来
    const emailTemplate = (toEmail, ccEmail, next) => {
      templateModel.findOne({ where: { id: item.templateId } }, (err, result) => {
        formDetail.createdAt = new Date(formDetail.createdAt);
        formDetail.formDetail.positionTitle = _.unescape(formDetail.formDetail.positionTitle);
        if (!_.isEmpty(err)) return next(err);
        try {
          const options = {
            from: process.env.EMAIL_SENDER,
            to: toEmail,
            subject: commonService.compileEmailTemplate(result.subject, { host: process.env.EMAIL_HOST, form, formDetail, requester, approver, nextApprover }),
            html: commonService.compileEmailTemplate(result.emailBody, { host: process.env.EMAIL_HOST, form, formDetail, requester, approver, nextApprover, approvalList }),
          };
          if (ccEmail.length > 0) {
            const ccEmailList = [];
            ccEmail.forEach((ccEmailItem) => {
              ccEmailList.push({ email: ccEmailItem });
            });
            options.cc = ccEmailList;
          }
          if (!_.isEmpty(result.priority)) {
            options.priority = result.priority;
          }
          commonService.sendEmail(options, error => !_.isEmpty(error) && console.log(error));
        } catch (error) {
          throw (error);
        }
      });
    };
    async.waterfall([to, cc, emailTemplate], err => err);
  });
}

function getStepEmailAcitonList(stepId, stepList, status, approvalStep) {
  console.log(status);
  let stepActionToList = '';
  _.forEach(stepList, (item) => {
    if (item.approvalStep == stepId) {
      _.forEach(item.emailSend, (item1) => {
        if (item1.status == status) {
          !item1.steps[approvalStep] ? stepActionToList = item1.steps[0] : stepActionToList = item1.steps[approvalStep];
        }
      });
    }
  });
  return stepActionToList;
}

handlebars.registerHelper('formatDate', date => date.toISOString().split('T')[0]);

handlebars.registerHelper('getApprovalHtml', (list, isEN) => {
  let html = '<br>';
  _.forEach(list, (item, index) => {
    if (index < list.length - 1) {
      const name = isEN ? item.approvalEnglishName : item.approvalName;
      const approver = isEN ? item.approver().englishName : item.approver().chineseName;
      html += `${name}:${approver}<br>`;
    }
  });
  return new handlebars.SafeString(html);
});

handlebars.registerHelper('getAllApprovalHtml', (list, isEN) => {
  let html = '<br>';
  _.forEach(list, (item, index) => {
    if (index < list.length) {
      const name = isEN ? item.approvalEnglishName : item.approvalName;
      const approver = isEN ? item.approver().englishName : item.approver().chineseName;
      html += `${name}:${approver}<br>`;
    }
  });
  return new handlebars.SafeString(html);
});

handlebars.registerHelper('formatProvinceAndCity', (province, city) => {
  let html = '';
  const specCities = ['北京', '上海', '天津', '重庆'];
  if (_.includes(specCities, province)) { html += `${province}市`; } else { html += `${province}省 ${city}市`; }
  return new handlebars.SafeString(html);
});

function handleCustomEvent(form, formDetail, eventName, callback) {
  if (!_.isEmpty(eventName) && _.isFunction(customEventService[eventName])) return customEventService[eventName](formDetail, callback);
  callback();
}

function handleConditionEvent(conditionItem, form, formDetail) {
  let judge = false;
  if (!conditionItem.isJudge) return !judge;
  const methodName = conditionItem.customMethod;
  if (!_.isEmpty(methodName) && _.isFunction(customConditionService[methodName])) judge = customConditionService[methodName](formDetail);
  return judge;
}

function getStaticFlowApprovalList(form, formDetail, callback) {
  try {
    const flow = form.flow();
    const flowList = [];
    let flowIndex = 0;
    let approvalFinalStep = 0;
    let approvalList = [];
    const conditionList = flow.flowRun.conditions;
    const getAllApprovalList = () => {
      const flowItem = flowList[flowIndex];
      if (_.isEmpty(flowItem)) return callback(null, approvalFinalStep, approvalList);
      getFlowItemApprovalList(form, formDetail, flowList, flowIndex, flowItem.approvalStep, (error, flowItemApprovalList) => {
        if (!_.isEmpty(error)) return callback(error);
        approvalList = approvalList.concat(flowItemApprovalList);
        flowIndex += 1;
        getAllApprovalList();
      });
    };
    _.forEach(conditionList, (conditionItem, index) => {
      if (handleConditionEvent(conditionItem, form, formDetail)) {
        flowList.push(flow.flowRun.steps[index]);
      }
    });
    approvalFinalStep = flowList.length;
    getAllApprovalList();
  } catch (error) {
    throw error;
  }
}

function getDynamicFlowApprovalList(form, formDetail, currentApprovalStep, callback) {
  try {
    const flowList = [];
    const flow = form.flow();
    const conditionList = flow.flowRun.conditions;
    let nextStepIndex = currentApprovalStep - 1;
    do {
      const conditionItem = conditionList[nextStepIndex];
      if (!_.isEmpty(conditionItem)) {
        if (handleConditionEvent(conditionItem, form, formDetail)) {
          flowList.push(flow.flowRun.steps[nextStepIndex]);
        } else {
          nextStepIndex += 1;
        }
      }
    } while (_.isEmpty(flowList) && nextStepIndex < conditionList.length);
    if (_.isEmpty(flowList)) {
      callback(null, currentApprovalStep - 1, [], nextStepIndex);
    } else {
      getFlowItemApprovalList(form, formDetail, flowList, 0, nextStepIndex + 1, (error, approvalList) => {
        callback(error, currentApprovalStep + 1, approvalList, nextStepIndex);
      });
    }
  } catch (error) {
    throw error;
  }
}

function getFlowItemApprovalList(form, formDetail, flowList, flowIndex, currentApprovalStep, callback) {
  const models = commonService.getModels();
  const { SysUserRoleMapping: userRoleMappingModel, SysUser: userModel } = models;
  const flow = form.flow();
  const isDynamicFlow = flow.flowRun.isDynamicFlow;
  const flowItem = flowList[flowIndex];
  const employeeId = _.get(formDetail.formDetail, `approvalStep${currentApprovalStep}Approver`);
  let roleIdList = _.get(formDetail.formDetail, `approvalStep${currentApprovalStep}Role`);
  let taskList = [];
  const getEmployeeIdListByEmployeeId = (next) => {
    next(null, [employeeId]);
  };
  const getEmployeeIdListByRoleIdList = (next) => {
    if (!_.isArray(roleIdList)) roleIdList = [roleIdList];
    commonService.getList(userRoleMappingModel, { where: { roleId: { inq: roleIdList } } }, (error, userRoleMappingList) => {
      next(error, _.flatMap(_.uniqBy(userRoleMappingList, 'userEmployeeId'), 'userEmployeeId'));
    });
  };
  const getEmployeeIdListByCurrentFlowItem = (next) => {
    getFlowItemApproverEmployeeIdList(flowItem, next);
  };
  const getApproverList = (employeeIdList, next) => {
    commonService.getList(userModel, { where: { employeeId: { inq: employeeIdList } } }, next);
  };
  const getApprovalList = (approverList, next) => {
    try {
      const approvalList = [];
      _.forEach(approverList, (approverItem) => {
        const approvalItem = createApprovalItem(form, form.flow(), formDetail, flowItem.approvalStep, approverItem, isDynamicFlow ? currentApprovalStep : flowIndex + 1);
        approvalList.push(approvalItem);
      });
      next(null, approvalList);
    } catch (error) {
      throw error;
    }
  };
  if (!_.isEmpty(employeeId)) {
    taskList.push(getEmployeeIdListByEmployeeId);
  } else if (!_.isEmpty(roleIdList)) {
    taskList.push(getEmployeeIdListByRoleIdList);
  } else {
    taskList.push(getEmployeeIdListByCurrentFlowItem);
  }
  taskList = taskList.concat([getApproverList, getApprovalList]);
  async.waterfall(taskList, callback);
}

function createApprovalItem(form, flow, formDetail, stepId, currentApprover, currentApprovalStep) {
  try {
    const approvalItem = {
      formId: form.id,
      flowId: flow.id,
      stepId,
      instanceId: formDetail.id,
      approvalStatus: enums.approvalStatus.pending,
      approvalStep: currentApprovalStep,
      prevApprovalStep: currentApprovalStep == 1 ? null : currentApprovalStep,
      nextApprovalStep: null,
      requesterEmployeeId: formDetail.sys_owner,
      approverEmployeeId: currentApprover.employeeId,
      approvalName: flow.flowRun.steps[stepId - 1].name,
      approvalEnglishName: flow.flowRun.steps[stepId - 1].englishName,
      comment: '',
    };
    return approvalItem;
  } catch (error) {
    throw error;
  }
}

function getFlowItemApproverEmployeeIdList(flowItem, callback) {
  let employeeIdList = [];
  const getFlowItemEmployeeIdList = (next) => {
    const concatEmployeeIdListByUsers = (next) => {
      getEmployeeIdListByUsers(flowItem, (error, approvalListByUsers) => {
        employeeIdList = employeeIdList.concat(approvalListByUsers);
        next(error);
      });
    };
    const concatEmployeeIdListByRoles = (next) => {
      getEmployeeIdListByRoles(flowItem, (error, approvalListByRoles) => {
        employeeIdList = employeeIdList.concat(approvalListByRoles);
        next(error);
      });
    };
    const concatEmployeeIdListBySql = (next) => {
      getEmployeeIdListBySql(flowItem, (error, approvalListBySql) => {
        employeeIdList = employeeIdList.concat(approvalListBySql);
        next(error);
      });
    };
    async.parallel({ concatEmployeeIdListByUsers, concatEmployeeIdListByRoles, concatEmployeeIdListBySql }, next);
  };
  const distinctEmployeeIdList = (result, next) => {
    try {
      employeeIdList = _.unionBy(employeeIdList);
      next(null, employeeIdList);
    } catch (error) {
      throw error;
    }
  };
  async.waterfall([getFlowItemEmployeeIdList, distinctEmployeeIdList], callback);
}

function getFormDetailApprovalList(formId, callback) {
  const models = commonService.getModels();
  const { SysUser: userModel } = models;
  const employeeIdList = [];
  let approverList = [];
  const getForm = (next) => {
    getFormIncludeAll(formId, next);
  };
  const getEmployeeIdList = (form, next) => {
    const flowList = form.flow().flowRun.steps;
    let stepIndex = 0;
    const getEveryFlowItemApproverEmployeeIdList = () => {
      try {
        const flowItem = flowList[stepIndex];
        if (_.isEmpty(flowItem)) return next(null);
        getFlowItemApproverEmployeeIdList(flowItem, (error, flowItemApproverEmployeeIdList) => {
          if (!_.isEmpty(error)) return next(error);
          employeeIdList[stepIndex] = flowItemApproverEmployeeIdList;
          stepIndex += 1;
          getEveryFlowItemApproverEmployeeIdList();
        });
      } catch (error) {
        throw error;
      }
    };
    getEveryFlowItemApproverEmployeeIdList();
  };
  const getApproverList = (next) => {
    let approverEmployeeIdList = [];
    _.forEach(employeeIdList, (flowItemApprovalList) => {
      _.forEach(flowItemApprovalList, (flowItemApprovalItem) => {
        approverEmployeeIdList.push(flowItemApprovalItem);
      });
    });
    approverEmployeeIdList = _.uniq(approverEmployeeIdList);
    commonService.getList(userModel, { where: { employeeId: { inq: approverEmployeeIdList }, include: ['lineManager', 'department', 'roleList'] } }, (error, userList) => {
      approverList = userList;
      next(error);
    });
  };
  const createApprovalList = (next) => {
    try {
      const approvalList = [];
      _.forEach(employeeIdList, (flowItemApprovalList, index) => {
        _.forEach(flowItemApprovalList, (flowItemApprovalItem) => {
          const user = _.filter(approverList, { employeeId: flowItemApprovalItem })[0];
          approvalList.push({
            id: user.employeeId,
            name: user.chineseName,
            user,
            approvalStep: (index + 1),
          });
        });
      });
      next(null, approvalList);
    } catch (error) {
      throw error;
    }
  };
  async.waterfall([getForm, getEmployeeIdList, getApproverList, createApprovalList], callback);
}

function getEmployeeIdListByUsers(flowItem, callback) {
  try {
    const approvalList = [];
    const behavior = flowItem.behavior;
    const userList = behavior.selectRange.users;
    _.forEach(userList, userItem => approvalList.push(userItem));
    callback(null, approvalList);
  } catch (error) {
    throw error;
  }
}

function getEmployeeIdListByRoles(flowItem, callback) {
  const { SysUserRoleMapping: userRoleMappingModel } = commonService.getModels();
  const approvalList = [];
  const behavior = flowItem.behavior;
  const roleList = behavior.selectRange.roles;
  if (_.isEmpty(roleList)) return callback(null, []);
  const getUserList = (next) => {
    const roleIdList = [];
    _.forEach(roleList, roleItem => roleIdList.push(roleItem));
    userRoleMappingModel.find({ where: { roleId: { inq: roleIdList } } }, next);
  };
  const getApprovalList = (userRoleMappingList, next) => {
    try {
      _.forEach(userRoleMappingList, userRoleMappingItem => approvalList.push(userRoleMappingItem.userEmployeeId));
      next(null, approvalList);
    } catch (error) {
      throw error;
    }
  };
  async.waterfall([getUserList, getApprovalList], callback);
}

function getEmployeeIdListBySql(flowItem, callback) {
  console.log('get employee id list by sql');
  callback(null, []);
}

function getFormNumber(formNumber) {
  if (formNumber.indexOf('{{moment}}') != -1) {
    const format = formNumber.match(/{{moment}}\w+{{\/moment}}/)[0].replace('{{moment}}', '').replace('{{/moment}}', '');
    formNumber = formNumber.replace(/{{moment}}\w+{{\/moment}}/, moment().format(format));
    const date = new Date();
    const newYear = date.getFullYear();
    const numericFormNumber = (`${global.prIdNumeric}`).length < 4 ? ((new Array(4 + 1)).join('0') + global.prIdNumeric).slice(-4) : `${global.prIdNumeric}`;
    formNumber = formNumber.replace(/0000/, `-${numericFormNumber}`);
    if (newYear != global.prIdOldYear) {
      global.prIdNumeric = 1;
      global.prIdOldYear = newYear;
    }
    global.prIdNumeric += 1;
  }
  return formNumber;
}

function getNewPrId() {
  const { WfRunInstance: formDetailModel } = models;
  formDetailModel.find({ where: { formId: 3 }, order: 'id desc', limit: 1 }, (err, result) => {
    global.prIdNumeric = Number(result[0].formNumber.split('-')[2]) + 1;
  });
}

function getFormIncludeAll(id, callback) {
  const models = commonService.getModels();
  const { WfForm: formModel } = models;
  commonService.getDetail(formModel, { where: { id, deleted: false }, include: ['flow'] }, callback);
}

function getFormDetailIncludeAll(formId, id, callback) {
  const models = commonService.getModels();
  const { WfRunInstance: formDetailModel } = models;
  let flow = {};
  const formDetail = {
    formDetail: {},
  };
  const getForm = (next) => {
    getFormIncludeAll(formId, next);
  };
  const getFormDetail = (form, next) => {
    flow = form.flow();
    if (id == 0) return next(null, formDetail);
    commonService.getDetail(formDetailModel, {
      where: { id },
      include: [
        'form',
        'flow',
        {
          relation: 'approvalList',
          scope: {
            where: { deleted: false },
            include: ['requester', 'approver'],
          },
        },
        'owner',
      ],
    }, next);
  };
  const getDefaultApprover = (formDetail, next) => {
    if (id != 0) return next(null, formDetail);
    try {
      const flowList = flow.flowRun.steps;
      _.forEach(flowList, (flowItem, index) => formDetail.formDetail[`approvalStep${index + 1}Approver`] = flowItem.behavior.defaultHandlerUser);
    } catch (error) {
      throw error;
    }
    next(null, formDetail);
  };
  async.waterfall([getForm, getFormDetail, getDefaultApprover], callback);
}

function getSubmitList(params, callback) {
  const { WfRunInstance: formDetailModel } = models;
  const getIdList = (next) => {
    params.employeeId = commonService.getEmployeeId();
    getSubmitSql(params, false, next);
  };
  const getSubmitList = (idList, next) => {
    if (idList.length == 0) return next(null, []);
    commonService.getList(formDetailModel, {
      where: { or: idList },
      order: 'createdAt desc',
      include: [
        'form',
        'flow',
        {
          relation: 'approvalList',
          scope: {
            where: { deleted: false },
            include: ['requester', 'approver'],
          },
        },
        'owner',
      ],
    }, next);
  };
  async.waterfall([getIdList, getSubmitList], callback);
}

function getSubmitListPageTotal(params, callback) {
  const getListCount = (next) => {
    params.employeeId = commonService.getEmployeeId();
    getSubmitSql(params, true, next);
  };
  async.waterfall([getListCount], (error, data) => {
    callback(error, _.ceil(_.toNumber(data[0].count) / _.toNumber(params.pageSize)));
  });
}

function getSubmitSql(params, isCount, callback) {
  let sql = `select ${isCount ? 'count(*)' : 'id'} from elanco_app.wf_run_instance`;
  const dataList = [];
  const pageNumber = _.toNumber(params.pageNumber);
  const pageSize = _.toNumber(params.pageSize);
  dataList.push(params.employeeId);
  sql += ` where sys_owner = $${dataList.length} and sys_deleted = false`;
  if (!_.isEmpty(params.formId)) {
    dataList.push(params.formId);
    sql += ` and form_id = $${dataList.length}`;
  }
  if (!_.isEmpty(params.formNumber)) {
    dataList.push(params.formNumber);
    sql += ` and form_number ~ $${dataList.length}`;
  }
  if (!_.isEmpty(params.formStatus)) {
    if (params.formStatus === 'saved') {
      dataList.push(-99);
      sql += ` and form_status = $${dataList.length}`;
    }
    if (params.formStatus === 'completed') {
      dataList.push(99);
      sql += ` and form_status = $${dataList.length}`;
    }
    if (params.formStatus === 'pending') {
      dataList.push(99);
      sql += ` and form_status not in ($${dataList.length}) and form_status >= 0`;
    }
    if (params.formStatus === 'reject') {
      dataList.push(-99);
      sql += ` and form_status not in ($${dataList.length}) and form_status < 0`;
    }
    // dataList.push(params.formStatus);
    //  sql += ` and form_status = $${dataList.length}`;
  }
  if (!_.isEmpty(params.detail)) {
    if (!_.isEmpty(params.detail.activityNameDescription)) {
      dataList.push(params.detail.activityNameDescription);
      sql += ` and form_detail ->> 'activityNameDescription' ~ $${dataList.length}`;
    }
  }
  if (!isCount) sql += ` order by sys_updated_at desc offset ${pageSize * (pageNumber - 1)} limit ${pageSize}`;
  commonService.executeSql(sql, dataList, callback);
}

function getApprovalList(params, callback) {
  const { WfRunInstance: formDetailModel } = models;
  const getIdList = (next) => {
    params.employeeId = commonService.getEmployeeId();
    getApprovalSql(params, false, next);
  };
  const getApprovalList = (idList, next) => {
    if (idList.length == 0) return next(null, []);
    commonService.getList(formDetailModel, {
      where: { or: idList },
      order: 'updatedAt desc',
      include: [
        'form',
        'flow',
        {
          relation: 'approvalList',
          scope: {
            where: { deleted: false },
            include: ['requester', 'approver'],
          },
        },
        'owner',
      ],
    }, next);
  };
  async.waterfall([getIdList, getApprovalList], callback);
}

function getApprovalListPageTotal(params, callback) {
  const getListCount = (next) => {
    params.employeeId = commonService.getEmployeeId();
    getApprovalSql(params, true, next);
  };
  async.waterfall([getListCount], (error, data) => {
    callback(error, _.ceil(_.toNumber(data[0].count) / _.toNumber(params.pageSize)));
  });
}

function getApprovalSql(params, isCount, callback) {
  let sql = `select ${isCount ? 'count(*)' : 'id'} from (select formDetail.id from elanco_app.wf_run_flow_detail approvalDetail
  inner join elanco_app.wf_run_instance formDetail on approvalDetail.instance_id = formDetail.id
  inner join elanco_sys.sys_user userDetail on approvalDetail.requester_employee_id = userDetail.employee_id`;
  const dataList = [];
  const pageNumber = _.toNumber(params.pageNumber);
  const pageSize = _.toNumber(params.pageSize);
  dataList.push(params.employeeId);
  sql += ` where approvalDetail.approver_employee_id = $${dataList.length} and formDetail.sys_deleted = false and approvalDetail.sys_deleted = false`;
  if (!_.isEmpty(params.formId)) {
    dataList.push(params.formId);
    sql += ` and approvalDetail.form_id = $${dataList.length}`;
  }
  if (!_.isEmpty(params.formNumber)) {
    dataList.push(params.formNumber);
    sql += ` and formDetail.form_number ~ $${dataList.length}`;
  }
  if (!_.isEmpty(params.approvalStatus)) {
    if (params.approvalStatus == enums.approvalStatus.pending) {
      sql += ' and approvalDetail.approval_step = formDetail.approval_step';
      dataList.push(enums.formStatus.submitted);
      sql += ` and formDetail.form_status >= $${dataList.length}`;
      dataList.push(enums.formStatus.completed);
      sql += ` and formDetail.form_status != $${dataList.length}`;
      dataList.push(params.approvalStatus);
      sql += ` and approvalDetail.approval_status = $${dataList.length}`;
    } else {
      sql += ' and approvalDetail.approval_step <= formDetail.approval_step';
      dataList.push(params.approvalStatus);
      sql += ` and approvalDetail.approval_status = $${dataList.length}`;
    }
  } else {
    sql += ' and approvalDetail.approval_step <= formDetail.approval_step';
  }
  if (!_.isEmpty(params.requesterEmployeeId)) {
    dataList.push(params.requesterEmployeeId);
    sql += ` and (approvalDetail.requester_employee_id = $${dataList.length} or userDetail.chinese_name ~ $${dataList.length} or userDetail.english_name ~ $${dataList.length})`;
  }
  if (!_.isEmpty(params.detail)) {
    if (!_.isEmpty(params.detail.activityNameDescription)) {
      dataList.push(params.detail.activityNameDescription);
      sql += ` and formDetail.form_detail ->> 'activityNameDescription' ~ $${dataList.length}`;
    }
    if (!_.isEmpty(params.detail.positionId)) {
      dataList.push(params.detail.positionId);
      sql += ` and formDetail.form_detail ->> 'positionId' ~ $${dataList.length}`;
    }
    if (!_.isEmpty(params.detail.hiringManager)) {
      dataList.push(params.detail.hiringManager);
      sql += ` and (formDetail.form_detail #>> '{ hiringManager, employeeId }' = $${dataList.length} or formDetail.form_detail #>> '{ hiringManager, chineseName }' ~ $${dataList.length} or formDetail.form_detail #>> '{ hiringManager, englishName }' ~ $${dataList.length})`;
    }
    if (!_.isEmpty(params.detail.requestDateStart)) {
      dataList.push(params.detail.requestDateStart);
      sql += ` and formDetail.request_date >= $${dataList.length}::timestamp`;
    }
    if (!_.isEmpty(params.detail.requestDateEnd)) {
      dataList.push(params.detail.requestDateEnd);
      sql += ` and formDetail.request_date < $${dataList.length}::timestamp + '1 day'`;
    }
  }
  sql += ' group by formDetail.id order by formDetail.sys_updated_at desc) as tab1';
  if (!isCount) sql += ` offset ${pageSize * (pageNumber - 1)} limit ${pageSize}`;
  commonService.executeSql(sql, dataList, callback);
}

module.exports = {
  handlEmailSendEvent,
  handleCustomEvent,
  sendEmailReminder,
  handleConditionEvent,
  getStaticFlowApprovalList,
  getDynamicFlowApprovalList,
  createApprovalItem,
  getFormDetailApprovalList,
  getFormNumber,
  getFormIncludeAll,
  getFormDetailIncludeAll,
  getSubmitList,
  getSubmitListPageTotal,
  getApprovalList,
  getApprovalListPageTotal,
  handlForwordEmailSendEvent,
  handlRevocationFormEmailSendEvent,
  getNewPrId,
};
